package com.ruoyi.mongo.word.service.impl;

import com.mongodb.client.result.UpdateResult;
import com.ruoyi.mongo.cet4.service.PrimaryInterface;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.mongo.service.MongoCommonService;
import com.ruoyi.mongo.service.MongoConstants;
import com.ruoyi.mongo.service.MongoService;
import com.ruoyi.mongo.config.QueryForm;
import com.ruoyi.mongo.word.entity.*;
import com.ruoyi.mongo.senior.service.SeniorInterface;
import com.ruoyi.mongo.word.service.WordListInterface;
import com.ruoyi.mongo.word.service.WordListMongoInterface;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.TimeZone;

@Slf4j
@Service
public class WordListMongoService implements WordListMongoInterface {

    @Autowired
    private MongoCommonService mongoCommonService;

    @Autowired
    private WordListInterface wordListInterface;

    @Autowired
    private SeniorInterface seniorInterface;

    @Autowired
    private PrimaryInterface primaryInterface;

    /**
     * 全部
     * 单词列表
     */
    @Override
    public List<?> getAllListData(String collectionName) {
        Query query = new Query();
        return mongoCommonService.getList(new WordEntity(), query, collectionName);
    }

    /**
     * 全部
     * 分页查询
     * 单词列表
     */
    @Override
    public List<?> getAllListDataByPage(String collectionName, int pageNum, int pageSize) {
        Query query = new Query();
        query.skip((long) (pageNum - 1) * pageSize);
        query.limit(pageSize);
        return mongoCommonService.getList(new WordEntity(), query, collectionName);
    }

    @Override
    public List<?> getAllListDataByUnit(String collectionName, String unit, String book) {
        Query query = new Query();
        query.addCriteria(Criteria.where(MongoConstants.MONGO_UNIT).is(unit));
        query.addCriteria(Criteria.where(MongoConstants.MONGO_BOOK).is(book));
        return mongoCommonService.getList(new WordEntity(), query, collectionName);
    }

    @Override
    public <T> List<?> getAllListData(T t, String collectionName, String unit, String book) {
        Query query = new Query();
        query.addCriteria(Criteria.where(MongoConstants.MONGO_UNIT).is(unit));
        query.addCriteria(Criteria.where(MongoConstants.MONGO_BOOK).is(book));
        return mongoCommonService.getList(t, query, collectionName);
    }

    @Override
    public List<?> getAllListDataByUnitCheck(String collectionName, String unit) {
        Query query = new Query();
        Criteria criteria = Criteria.where(MongoConstants.MONGO_UNIT).is(unit);
        query.addCriteria(criteria);
        //根据登录用户创建学习记录
        Long userId = SecurityUtils.getLoginUser().getUserId();

        Long count = mongoCommonService.getCount(new WordTestEntity(), query, collectionName + "_test_" + userId);
        Long serviceCount = mongoCommonService.getCount(new WordEntity(), query, collectionName);

        long subtractExact = Math.subtractExact(count, serviceCount);
        if (Math.abs(subtractExact) < 5) {
            // 两次数据差别不大
            log.info("测试过的记录和标准的数据条数差别小于5");
            long floored = Math.floorDiv(serviceCount, 2);
            Aggregation aggregation = Aggregation.newAggregation(Aggregation.match(criteria), Aggregation.sample(floored));
            AggregationResults<?> results = mongoCommonService.getAggregationResults(new WordStudyEntity(), aggregation, collectionName + "_test_" + userId);
            return results.getMappedResults();
        } else {
            log.info("返回标准的数据条数");
            return mongoCommonService.getList(new WordEntity(), query, collectionName);
        }
    }

    @Override
    public List<?> getAllListDataByUnitCheck(String collectionName, String unit, String book, int times, Integer pageNum) {
        Query query = new Query();
        Criteria criteria = new Criteria();
        if (book != null && !book.isEmpty()) {
            criteria = Criteria.where(MongoConstants.MONGO_BOOK).is(book);
        }
        if (unit != null && !unit.isEmpty()) {
            criteria.and(MongoConstants.MONGO_UNIT).is(unit);
        }
        else {
            query.limit(MongoConstants.MONGO_MAX_QUERY_SIZE);
        }
        query.addCriteria(criteria);
        if (pageNum != null) {
            query.skip((long) (pageNum - 1) * MongoConstants.MONGO_PAGE_SIZE);
            query.limit(MongoConstants.MONGO_PAGE_SIZE);
        }
        Long serviceCount = mongoCommonService.getCount(new WordEntity(), query, collectionName);
        if (times == 1) {
            return mongoCommonService.getList(new WordEntity(), query, collectionName);
        } else {
            long floored = Math.floorDiv(serviceCount, times);
            Aggregation aggregation = Aggregation.newAggregation(Aggregation.match(criteria), Aggregation.sample(floored));
            AggregationResults<?> results = mongoCommonService.getAggregationResults(new WordStudyEntity(), aggregation, collectionName);
            return results.getMappedResults();
        }
    }

    /**
     * 听力练习
     * 默认条数-30
     * 返回数据随机
     * 列表
     */
    @Override
    public List<?> getHearList(Integer times) {
        Query query = new Query();
        Criteria criteria = new Criteria();
        query.addCriteria(criteria);
        long simpleNum;
        if (times != null) {
            simpleNum = times.longValue();
        } else {
            simpleNum = MongoConstants.MONGO_DEFAULT_SIZE;
        }
        Aggregation aggregation = Aggregation.newAggregation(Aggregation.match(criteria), Aggregation.sample(simpleNum));
        AggregationResults<?> results = mongoCommonService.getAggregationResults(new WordHearEntity(), aggregation, MongoConstants.COLLECT_WORD_HEAR);
        List<?> list = results.getMappedResults();
        long number = times == null ? MongoConstants.MONGO_DEFAULT_SIZE : times;
        log.info("查询-听力列表-条数:{}-结果:{}", number, !list.isEmpty());
        return list;
    }

    /**
     * 听力练习
     * 通过分组(1-50)
     * 列表
     */
    @Override
    public List<?> getHearListByGroup(String group) {
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and("group").is(group);
        query.addCriteria(criteria);
        Long simpleNum = mongoCommonService.getCount(new WordHearEntity(), query, MongoConstants.COLLECT_WORD_HEAR);

        Aggregation aggregation = Aggregation.newAggregation(Aggregation.match(criteria), Aggregation.sample(simpleNum));
        AggregationResults<?> results = mongoCommonService.getAggregationResults(new WordHearEntity(), aggregation, MongoConstants.COLLECT_WORD_HEAR);
        List<?> list = results.getMappedResults();
        log.info("查询-听力-条件:{}-条数:{}-结果:{}", query.getQueryObject().toJson(), simpleNum, !list.isEmpty());
        return list;
    }

    /**
     * 听力练习
     * 查询
     * 单个记录
     * 需要修改
     */
    @Override
    public WordHearRecord getHearOne(String id) {
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and("basicId").is(id);
        query.addCriteria(criteria).limit(1);
        Long userId = SecurityUtils.getLoginUser().getUserId();
        String name = MongoConstants.COLLECT_WORD_HEAR_RECORD + "_" + userId;
        return (WordHearRecord) mongoCommonService.getOne(new WordHearRecord(), query, name);
    }

    /**
     * 听力练习
     * 保存
     * 单个记录
     */
    @Override
    public void putHearData(WordHearRecord entity) {
        //根据登录用户创建学习记录
        Long userId = SecurityUtils.getLoginUser().getUserId();
        String name = MongoConstants.COLLECT_WORD_HEAR_RECORD + "_" + userId;
        entity.set_id(null);
        entity.setTime(DateUtils.getTime());
        entity.setUpdateTimes(0);
        entity.setResult(entity.getNameAgain().equalsIgnoreCase(entity.getName()));
        WordHearRecord record = mongoCommonService.insertOne(entity, name);
        log.info("集合:{}-时间:{}-插入了一条记录,主键:{}", name, DateUtils.getLocalTime(), record.get_id());
    }

    /**
     * 听力练习
     * 更新
     * 单个记录
     */
    @Override
    public void updateHearData(WordHearRecord entity) {
        //根据登录用户创建学习记录
        Long userId = SecurityUtils.getLoginUser().getUserId();
        String name = MongoConstants.COLLECT_WORD_HEAR_RECORD + "_" + userId;
        entity.setTime(DateUtils.getTime());
        entity.setResult(entity.getNameAgain().equalsIgnoreCase(entity.getName()));
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(entity.get_id()));
        Update update = new Update();
        update.set(MongoConstants.MONGO_RANK_HEAR_RESULT, entity.getNameAgain().equalsIgnoreCase(entity.getName()));
        update.set(MongoConstants.MONGO_RANK_HEAR_NAME_INPUT, entity.getNameAgain());
        int times = entity.getUpdateTimes() + 1;
        update.set(MongoConstants.MONGO_RANK_HEAR_UPDATE_TIMES, times);
        update.set(MongoConstants.MONGO_RANK_HEAR_HEARD_TIMES, entity.getHeardTimes());
        mongoCommonService.insertOrUpdate(entity, query, update, name);
        log.info("集合:{}-时间:{}-更新了一条记录,次数:{}", name, DateUtils.getTime(), times);
    }

    /**
     * 分页查询
     */
    @Override
    public List<?> getAllListDataByPage(String collectionName, QueryForm queryForm) {
        int pageSize = queryForm.getPageSize();
        int pageNum = queryForm.getPageNum();
        return getAllListDataByPage(collectionName, pageNum, pageSize);
    }

    /**
     * 按单词词性查询
     * adj , n , v
     * 单词列表
     */
    @Override
    public List<?> getListData(String collectionName, String type) {
        Query query = new Query();
        Criteria criteria = Criteria.where(MongoConstants.MONGO_TYPE).is(type);
        query.addCriteria(criteria);
        return mongoCommonService.getList(new WordEntity(), query, collectionName);
    }

    @Override
    public void insertTestList(List<WordTestEntity> list, String collectionName) {
        mongoCommonService.insertList(list);
    }

    @Override
    public void removeTestData(String collectionName, String id) {
        Query query = new Query();
        query.addCriteria(Criteria.where(MongoConstants.MONGO_ID).is(id));
        //根据登录用户创建学习记录
        Long userId = SecurityUtils.getLoginUser().getUserId();
        mongoCommonService.deleteOne(collectionName + "_" + userId, query);
    }

    @Override
    public WordStudyEntity insertStudyData(WordStudyEntity entity, String collectionName) {
        //根据登录用户创建学习记录
        Long userId = SecurityUtils.getLoginUser().getUserId();
        String name = collectionName + "_" + userId;
        entity.setTime(DateUtils.getTime());
        WordStudyEntity studyEntity = mongoCommonService.insertOneAndReturn(entity, name);
        log.info("集合:{},插入,时间:{},主键:{}", name, DateUtils.getTime(), studyEntity.get_id());
        return studyEntity;
    }

    @Override
    public void insertStudyData(WordChinToEngEntity entity, String collectionName) {
        Long userId = SecurityUtils.getLoginUser().getUserId();
        String name = collectionName + "_" + userId;
        entity.setTime(DateUtils.getLocalTime());
        entity.set_id(null);
        WordChinToEngEntity studyEntity = mongoCommonService.insertOneAndReturn(entity, name);
        log.info("集合:{},插入,时间:{},主键:{}", name, DateUtils.getTime(), studyEntity.get_id());
    }

    @Override
    public void insertStudyList(List<WordStudyEntity> list, String collectionName) {
        //根据登录用户创建学习记录
        Long userId = SecurityUtils.getLoginUser().getUserId();
        mongoCommonService.insertList(list, collectionName + "_" + userId);
    }

    @Override
    public ArrayList<UpdateResult> insertOrUpdateTestList(WordTestEntity item, String collectionName) {
        ArrayList<UpdateResult> updateResults = new ArrayList<>();

        //根据登录用户创建学习记录
        Long userId = SecurityUtils.getLoginUser().getUserId();

        Query query = new Query();
        query.addCriteria(Criteria.where(MongoConstants.MONGO_ID).is(item.get_id()));

        Update update = new Update();
        update.set(MongoConstants.MONGO_STATUS, item.getStatus());
        update.set(MongoConstants.MONGO_NAME, item.getName());
        update.set(MongoConstants.MONGO_TYPE, item.getType());
        update.set(MongoConstants.MONGO_MEAN, item.getChinese());
        update.set(MongoConstants.MONGO_BOOK, item.getBook());
        update.set(MongoConstants.MONGO_UNIT, item.getUnit());
        update.set(MongoConstants.MONGO_NUMBER, item.getNumber());

        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
        update.set(MongoConstants.MONGO_UPDATE_TIME, LocalDateTime.now());
        if (ObjectUtils.isEmpty(item.getCreateTime())) {
            update.set(MongoConstants.MONGO_CREATE_TIME, LocalDateTime.now());
        }

        UpdateResult updateResult = mongoCommonService.insertOrUpdate(item, query, update, collectionName + "_" + userId);
        updateResults.add(updateResult);

        return updateResults;
    }

    @Override
    public ArrayList<UpdateResult> insertOrUpdateTestList(List<WordTestEntity> entityList, String collectionName) {
        ArrayList<UpdateResult> updateResults = new ArrayList<>();

        //根据登录用户创建学习记录
        Long userId = SecurityUtils.getLoginUser().getUserId();

        log.info("插入或更新的集合:{}", collectionName + "_" + userId);
        entityList.forEach(item -> {
            insertOrUpdateTestList(item, collectionName);
        });
        return updateResults;
    }

    @Override
    public List<?> getListTestData(String collectionName, String type, String book, Integer pageNum) {

        Query query = getListTestDataQuery(type, book, null, pageNum);

        //根据登录用户查询学习记录
        Long userId = SecurityUtils.getLoginUser().getUserId();

        return mongoCommonService.getList(new WordTestEntity(), query, collectionName + "_" + userId);
    }

    private Query getListTestDataQuery(String type, String book, String unit, Integer pageNum) {
        Query query = new Query();
        if (book != null && !book.isEmpty()) {
            query.addCriteria(Criteria.where(MongoConstants.MONGO_BOOK).is(book));
        }
        if (type != null && !type.isEmpty()) {
            Criteria criteria = Criteria.where(MongoConstants.MONGO_STATUS).is(type);
            query.addCriteria(criteria);
        }

        if (pageNum != null) {
            query.skip((long) (pageNum - 1) * MongoConstants.MONGO_PAGE_SIZE);
            query.limit(MongoConstants.MONGO_PAGE_SIZE);
        }
        return query;
    }

    @Override
    public List<?> getListTestData(String collectionName, String type, String book, String unit, Integer pageNum) {
        Query query = getListTestDataQuery(type, book, unit, pageNum);
        //根据登录用户查询学习记录
        Long userId = SecurityUtils.getLoginUser().getUserId();

        return mongoCommonService.getList(new WordTestEntity(), query, collectionName + "_" + userId);
    }

    @Override
    public List<?> getTestDetailsList(String status, String practice, int way) {
        //根据登录用户查询记录
        Long userId = SecurityUtils.getLoginUser().getUserId();

        Query query = wordListInterface.getRecordDetailQuery(status, practice);

        List<?> list;
        if (way == 2 || way == 3) {
            list = mongoCommonService.getList(new WordCheckNewRecord(), query, MongoConstants.COLLECT_WORD_CHECK_NEW_RECORD + "_" + userId);
        } else {
            list = mongoCommonService.getList(new WordCheckRecordEntity(), query, MongoConstants.COLLECT_WORD_CHECK_RECORD + "_" + userId);
        }
        return list;

    }

    @Override
    public List<?> getWriteDetailsList(String status, String practice) {
        //根据登录用户查询记录
        Long userId = SecurityUtils.getLoginUser().getUserId();

        Query query = wordListInterface.getRecordDetailQuery(status, practice);

        List<?> list;
        list = mongoCommonService.getList(new WordChinToEngEntity(), query, MongoConstants.COLLECT_WORD_CHIN_TO_ENG + "_" + userId);
        return list;
    }

    @Override
    public List<?> getWriteDetailsList(int user, String practice) {

        Query query = wordListInterface.getRecordDetailQuery(practice);

        List<?> list;
        list = mongoCommonService.getList(new WordChinToEngEntity(), query, MongoConstants.COLLECT_WORD_CHIN_TO_ENG + "_" + user);
        return list;
    }

    @Override
    public List<?> getTestDetailsListByUser(int userId, int way, String type, String practice) {
        Query query = wordListInterface.getRecordDetailQuery(null, practice);
        List<?> list;

        if (way == 3 && type.equals(MongoConstants.COLLECT_WORD_PRIMARY)){
           list = primaryInterface.getTestDetail(practice, (long) userId);
           if (list.isEmpty()){
               list = mongoCommonService.getList(new WordCheckNewRecord(), query, MongoConstants.COLLECT_WORD_CHECK_NEW_RECORD + "_" + userId);
           }
           return list;
        }

        if (way == 4){
            list = seniorInterface.selectListByPracticeId(practice, userId);
        }
        else if (way == 2 || way == 3) {
            list = mongoCommonService.getList(new WordCheckNewRecord(), query, MongoConstants.COLLECT_WORD_CHECK_NEW_RECORD + "_" + userId);
        } else {
            list = mongoCommonService.getList(new WordCheckRecordEntity(), query, MongoConstants.COLLECT_WORD_CHECK_RECORD + "_" + userId);
        }
        return list;
    }

    @Override
    public List<?> getStudyDetailsListByUser(int userId, String practice,int way) {
        Query query = wordListInterface.getRecordDetailQuery(null, practice);
        List<?> list ;
        if (way == 4){
            list = seniorInterface.selectStudyDetailByPractice(practice, (long) userId);
        } else if (way == 3) {
            list = primaryInterface.getStudyData(practice, (long) userId);
        } else {
            list = mongoCommonService.getList(new WordStudyEntity(), query, MongoConstants.COLLECT_WORD_STUDY + "_" + userId);
        }
        return list;
    }

    @Override
    public List<?> getHearDetailsList(String status, String practice) {
        //根据登录用户查询学习记录
        Long userId = SecurityUtils.getLoginUser().getUserId();

        Query query = wordListInterface.getRecordDetailQuery(status, practice);

        return mongoCommonService.getList(new WordHearRecord(), query, MongoConstants.COLLECT_WORD_HEAR_RECORD + "_" + userId);
    }

    @Override
    public List<?> getHearDetailsListByUser(int userId, String practice) {
        Query query = wordListInterface.getRecordDetailQuery(null, practice);
        return mongoCommonService.getList(new WordHearRecord(), query, MongoConstants.COLLECT_WORD_HEAR_RECORD + "_" + userId);
    }

    @Override
    public List<?> getListStudyData(String collectionName, String unit, String book, Integer pageNum) {
        Query query = MongoService.getDataCommon(unit, book);
        if (pageNum != null) {
            query.skip((long) (pageNum - 1) * MongoConstants.MONGO_PAGE_SIZE);
            query.limit(MongoConstants.MONGO_PAGE_SIZE);
        }
        Sort sort = Sort.by(Sort.Direction.DESC, MongoConstants.MONGO_TIME_SORTED);
        query.with(sort);
        //根据登录用户查询学习记录
        Long userId = SecurityUtils.getLoginUser().getUserId();

        return mongoCommonService.getList(new WordStudyEntity(), query, collectionName + "_" + userId);
    }

    /**
     * 经过4个选项测试后的数据存入数据库
     */
    @Override
    public void insertCheckRecord(WordCheckRecordEntity entity, String collectionCheckRecord) {
        entity.set_id(null);
        //根据登录用户创建学习记录
        Long userId = SecurityUtils.getLoginUser().getUserId();
        String name = collectionCheckRecord + "_" + userId;
        WordCheckRecordEntity record = mongoCommonService.insertOne(entity, name);
        log.info("集合:{}-时间:{}-插入了一条记录,主键:{}", name, DateUtils.getLocalTime(), record.get_id());
    }
}
